<template>
    <div class="slider">
        <div class="bar" ref="slider" @click.self="sliderClick">
            <div class="process" :style="barStyle" @click.self="sliderClick"></div>
            <div class="thunk" :style="{left: minPostion + '%'}"
            @touchstart="onPointerDown"
            @mousedown="onPointerDown">
                <div class="btn"></div>
                <div class="tips">
                    <span>{{currentValue}}</span>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'BcSlider',
    props: {
        min: {
            type: Number,
            default: 0
        },
        max: {
            type: Number,
            default: 100
        },
        value: {
            type: [Number, Array],
            default: 0
        },
        step: {
            type: Number,
            default: 1
        },
        disable: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            startX: 0,
            currentX: 0,
            startPos: 0,
            currentValue: this.value,
            dragging: true,
            sliderWidth: 0
        }
    },
    mounted() {
        let width = this.$refs.slider.offsetWidth;
        this.sliderWidth = parseInt(width, 10);
    },
    computed: {
        valueRange() {
            return this.max - this.min;
        },
        barStyle() {
            const style = {
                width: (this.currentValue - this.min) / this.valueRange * 100 + "%"
            };
            return style;
        },
        minPostion() {
            return (this.currentValue - this.min) / this.valueRange * 100;
        }
    },
    methods: {
        getPointerX(e) {
            return e.type.indexOf("touch") !== -1 ? e.touches[0].clientX : e.clientX;
        },
        checkLimits(cur) {
            let per = Math.max(this.min, cur);
            per = Math.min(this.max, per);
            return per;
        },
        onPointerDown(e) {
            if(this.disabled) return;
            event.preventDefault();
            this.onPointerDragStart(e);
            window.addEventListener("mousemove", this.onPointerDrag);
            window.addEventListener("touchmove", this.onPointerDrag);
            window.addEventListener("mouseup", this.onPointerDragEnd);
            window.addEventListener("touchend", this.onPointerDragEnd);
        },
        onPointerDragStart (e) {
            this.dragging = false;
            this.startX = this.getPointerX(e);
            this.startPos = (this.minPostion * this.valueRange / 100) + this.min;
        },
        onPointerDrag(e) {
            this.dragging = true;
            this.currentX = this.getPointerX(e);
            const diff = (this.currentX - this.startX) / this.sliderWidth * this.valueRange;
            this.changeButtonPosition(this.startPos + diff);
        },
        onPointerDragEnd() {
            if (this.dragging) {
                this.dragging = false;
                this.emitChange();
            }
            window.removeEventListener("mousemove", this.onPointerDrag);
            window.removeEventListener,("touchmove", this.onPointerDrag);
            window.removeEventListener,("mouseup", this.onPointerDragEnd);
            window.removeEventListener,("touchend", this.onPointerDragEnd);
        },
        changeButtonPosition(newPos) {
            const modules = this.handleDemcimal(newPos, this.step);
            let value = this.checkLimits(newPos - modules);
            this.currentValue = value;
        },
        handleDemcimal(pos, step) {
            if (step < 1) {
                let sl = step.toString(), multiple = 1, m;
                try {
                    m = sl.split(".")[1].length;
                } catch(e) {
                    m = 0;
                }
                multiple = Math.pow(10, m);
                return ((pos * multiple) % (step * multiple)) / multiple;
            } else return pos % step;
        },
        emitChange() {
            const value = this.currentValue;
            this.$emit("on-change", value);
        },
        sliderClick(e) {
            if (this.disabled) return;
            const currentX = this.getPointerX(e);
            const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
            let newPos = ((currentX - sliderOffsetLeft) / this.sliderWidth * this.valueRange) + this.min;
            this.changeButtonPosition(newPos);
        }
    }
}
</script>

<style scoped>
.slider .bar {
    position: relative;
    width: 100%;
    height: 4px;
    border-radius: 2px;
    background: #e8eaec;
}
.slider .process {
    position: absolute;
    top: 0;
    left: 0;
    height: 4px;
    border-radius: 2px;
    background: #57a3f3;
    /* width: 20px; */
}
.slider .thunk {
    position: absolute;
    /* top = -(14-4)/2 */
    top: -5px;
    height: 14px;
    width: 14px;
    text-align: center;
    transform: translateX(-50%);
    background: transparent;
}
.slider .btn {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: #fff;
    border: 2px solid #57a3f3;
}
.slider .tips {
    position: absolute;
    bottom: 20px;
    /* left = -(30-14)/2 */
    left: -8px;
    width: 30px;
    height: 20px;
    min-width: 20px;
    text-align: center;
    font-size: 16px;
    color: #57a3f3;
}
.slider .btn:hover {
    transform: scale(1.2);
}

</style>


